import { Monitor } from ".."
import { MonitorConfig } from "../config"
import { trackCoreWebVitals } from "./core-web-vitals"
import { trackLongTasks } from "./long-tasks"
import { trackNavigationTiming } from "./navigation"
import { PerformanceDataType } from "./performance-type"
import { trackResourceTiming } from "./resources"

export class PerformanceTracking {
    monitor: InstanceType<typeof Monitor>
    private queue: PerformanceDataType[] = []
    private readonly MAX_QUEUE_SIZE = 50
    private readonly FLUSH_INTERVAL = 180_000 // 60秒批量上报一次
    private flushInterval: NodeJS.Timeout | null = null

    // PV和停留时间相关状态
    private pvCount = 0
    private lastUrl = ""
    private isFirstLoad = true
    private lastPvTime = 0 // 用于统计用户在页面上的停留时间
    private isFlushing = false // 锁

    // report: (type: string, data: any) => void
    constructor(monitor: InstanceType<typeof Monitor>) {
        this.monitor = monitor
        // this.report = report

        this.init()
        this.startFlushTimer()
        this.setupRouterListener() // 初始化路由监听
        this.setupUnloadHandler() // 初始化卸载监听
    }

    private init() {
        // 核心 web 指标 （LCP、FCP、FID、CLS）
        trackCoreWebVitals(metric => this.report("core-vitals", metric))
        // 导航倒计时（TTFB、DNS、TCP等）
        trackNavigationTiming(metric => this.report("navigation", metric))
        // 静态资源加载监控
        trackResourceTiming(metric => this.report("resource", metric))
        // 长任务监控（主线程阻塞 > 50ms）
        trackLongTasks(metric => this.report("longtask", metric))
        // 初始PV统计
        this.trackPV()
    }

    private setupRouterListener() {
        // 监听React Router的路由变化
        const originalPushState = history.pushState
        const originalReplaceState = history.replaceState

        // 重写pushState方法
        history.pushState = (...args) => {
            originalPushState.apply(history, args)
            this.handleRouteChange()
        }

        // 重写replaceState方法
        history.replaceState = (...args) => {
            originalReplaceState.apply(history, args)
            this.handleRouteChange()
        }

        // 监听浏览器前进/后退
        window.addEventListener("popstate", this.handleRouteChange)
    }

    private handleRouteChange = () => {
        this.trackPV()
    }

    private trackPV() {
        const now = Date.now()
        const currentUrl = window.location.href

        // 上报停留时间（首次加载不报）
        if (!this.isFirstLoad && this.lastPvTime > 0) {
            this.report("stay_duration", {
                duration: now - this.lastPvTime,
                from: this.lastUrl,
                to: currentUrl
            })
        }

        // 更新状态
        this.pvCount++
        this.lastPvTime = now
        this.lastUrl = currentUrl
        this.isFirstLoad = false

        // 上报PV数据
        this.report("pv", {
            count: this.pvCount,
            isCache: this.checkIfPageLoadedFromCache(),
            time: now,
            url: currentUrl
        })
    }

    private checkIfPageLoadedFromCache(): boolean {
        const navEntries = performance.getEntriesByType("navigation")
        if (navEntries.length > 0) {
            const navigationEntry = navEntries[0] as PerformanceNavigationTiming
            return navigationEntry.transferSize === 0
        }
        return false
    }

    private report(type: string, data: any) {
        // 对资源数据特殊处理
        if (type === "resource") {
            // 合并相同URL资源的上报（取平均值）
            const existingIndex = this.queue.findIndex(item => item.type === "resource" && item.data.name === data.name)
            if (existingIndex >= 0) {
                const existing = this.queue[existingIndex]
                existing.data.duration = (existing.data.duration + data.duration) / 2
                return
            }
        }

        const payload: PerformanceDataType = {
            category: "performance",
            type,
            data,
            time: Date.now(),
            page: window.location.href,
            uuid: `${type}-${data.name || data.startTime || Date.now()}-${Math.random().toString(36).slice(2, 8)}`, // 生成唯一ID用于去重
            appId: this.monitor.options.appId
        }
        this.addToQueue(payload)
    }

    /**
     * 在 JavaScript 中，Array.prototype.some() 是一个数组方法，用于测试数组中的元素是否满足某个条件。
     * 它会遍历数组，并对每个元素执行一个测试函数。如果测试函数对 任何一个元素 返回 true，some() 方法就会立即返回 true；
     * 如果所有元素都不满足条件，则返回 false
     */

    private addToQueue(data: PerformanceDataType) {
        // 去重逻辑（避免重复上报相同的指标）
        if (this.queue.some(item => item.uuid === data.uuid)) return

        this.queue.push(data)

        // 队列达到阈值时就立即上报
        if (this.queue.length >= this.MAX_QUEUE_SIZE) {
            this.flushQueue()
        }
    }

    private startFlushTimer() {
        this.flushInterval = setInterval(() => {
            if (this.queue.length > 0) {
                this.flushQueue()
            }
        }, this.FLUSH_INTERVAL)
    }

    // 指数退避重试机制
    private async flushQueue() {
        if (this.isFlushing) return
        this.isFlushing = true

        // 最大重试次数
        const MAX_RETRY = 1
        // 当前重试次数
        let retryCount = 0
        // 创建队列的副本，用于发送
        const queueToSend = [...this.queue]
        let sendSuccess = false

        try {
            // 只要重试次数小于最大重试次数
            while (retryCount < MAX_RETRY && !sendSuccess) {
                try {
                    // 尝试发送数据
                    await this.monitor.transport?.sendPerformance(queueToSend)
                    sendSuccess = true
                    // 发送成功后，从队列中移除已发送的数据
                    this.queue = this.queue.filter(item => !queueToSend.includes(item))
                } catch (err) {
                    // 增加重试次数
                    retryCount++
                    if (retryCount > MAX_RETRY) {
                        console.error("[Monitor] 上报失败，重新加入队列:", err)
                        // 保留原始数据，不需要unshift
                        break // 不再重试
                    }
                    // 指数退避策略，等待一段时间后重试
                    await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, retryCount))) // 指数避让
                }
            }
        } finally {
            this.isFlushing = false
        }
    }

    private setupUnloadHandler() {
        window.addEventListener("beforeunload", () => {
            if (this.queue.length > 0) {
                try {
                    // 将数据转换为 Blob
                    const data = new Blob([JSON.stringify(this.queue)], { type: "application/json" })
                    // 确保 URL 是有效的
                    const url = MonitorConfig.performanceUrl
                    // 使用 sendBeacon 发送数据
                    if (navigator.sendBeacon(url, data)) {
                        this.queue = [] // 清空队列
                    } else {
                        console.warn("Beacon 数据发送失败")
                    }
                } catch (e) {
                    console.error("Beacon 上报失败:", e)
                }
                clearInterval(this.flushInterval as NodeJS.Timeout)
            }
        })
    }
}
